package max.cute.java8inaction.chap6;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

import static max.cute.java8inaction.chap6.Dish.menu;
/**
 * 广义的归约汇总
 *
 * 事实上，我们已经讨论的所有收集器，都是一个可以用reducing工厂方法定义的归约过程的特殊情况而已。
 * Collectors.reducing工厂方法是所有这些特殊情况的一般化。
 * 可以说，先前讨论的案例仅仅是为了方便程序员而已。
 * (但是，请记得方便程序员和可读性是头等大事!)例如，
 * 可以用reducing方法创建的收集器来计算你菜单的总热量，如下所示:
 *
 * int totalCalories = menu.stream().collect(reducing(0, Dish::getCalories, (i, j) -> i + j));
 *
 * 它需要三个参数。
 * 第一个参数是归约操作的起始值，也是流中没有元素时的返回值，所以很显然对于数值和而言0是一个合适的值。
 *
 * 第二个参数就是你在6.2.2节中使用的函数，将菜肴转换成一个表示其所含热量的int。
 *
 * 第三个参数是一个BinaryOperator，将两个项目累积成一个同类型的值。这里它就是对两个int求和。
 *
 * 同样，你可以使用下面这样单参数形式的reducing来找到热量最高的菜，如下所示:
 *      Optional<Dish> mostCalorieDish = menu.stream().collect(reducing((d1, d2) -> d1.getCalories() > d2.getCalories() ? d1 : d2));
 *
 *
 */
public class Reducing {

    public static void main(String[] args) {
        calcTotalCalories();
        System.out.println("- - - - - - ");
        calcMaxCaloriesDish();
        System.out.println("- - - - - - ");
        reducingArrayList();
        System.out.println("- - - - - - ");
    }

    private static void calcTotalCalories() {
        int totalCalories = menu.stream().collect(Collectors.reducing(0,Dish::getCalories,(c1,c2) -> c1 + c2));
        System.out.println(totalCalories);
    }

    private static void calcMaxCaloriesDish() {
        Optional<Dish> optionalDish = menu.stream().collect(Collectors.reducing((dish, dish2) -> dish.getCalories() > dish2.getCalories() ? dish : dish2));
        System.out.println(optionalDish.get());
    }

    private static void reducingArrayList() {
        Stream<Integer> stream = IntStream.rangeClosed(1,5).boxed();
        List<Integer> list = stream.reduce(new ArrayList<Integer>(),
                (List<Integer> lst, Integer val) -> {lst.add(val);return lst;},
                (List<Integer> lst1,List<Integer> lst2) -> {lst1.addAll(lst2); return lst1;});
        System.out.println(list);
    }
}
